package com.greedy.bulls.stock.user.minio;

import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Yanxy
 * @Date: Created in:2023-08-05
 * Description: minIo
 */
@Slf4j
@Component
public class MinioOperator {

    @Resource
    private MinioConfig minioConfig;

    @Resource
    private MinioClient minioClient;

    /**
     * 上传文件
     *
     * @param customFileName 自定义文件名
     * @param files          多文件
     * @param bucket         所属模块
     * @return 文件信息
     */
    public List<HashMap<String, String>> uploadFile(String customFileName, MultipartFile[] files, String bucket) {
        if (Objects.nonNull(files) && files.length > 0) {
            String bucketName = isNotNullOrEmpty(bucket) ? bucket.replaceAll(",", "") : minioConfig.getBucketName();
            List<HashMap<String, String>> resultList = new ArrayList<>();
            String fileName = null;
            for (MultipartFile file : files) {
                try {
                    if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                    }
                    fileName = file.getOriginalFilename();
                    if (isNotNullOrEmpty(customFileName)) {
                        fileName = customFileName;
                    }
//                    StringBuffer fileNameSb = new StringBuffer();
//                    fileNameSb.append(System.currentTimeMillis()).append("_").append(bucketName).append("_");
//                    if (isNotNullOrEmpty(fileName)) {
//                        fileNameSb.append(fileName.replaceAll(",", ""));
//                    }
//                    fileName = fileNameSb.toString();
                    PutObjectArgs args = PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build();
                    minioClient.putObject(args);
                    HashMap<String, String> map = new HashMap<>(3);
                    map.put("fileName", fileName);
                    map.put("bucketName", bucketName);
                    map.put("previewUrl", getPreviewUrl(fileName, bucketName));
                    resultList.add(map);
                    log.info("文件上传成功，文件名称：{}，bucket名称：{}", fileName, bucketName);
                } catch (Exception e) {
                    log.error("文件上传失败，文件名称：{}，bucket名称：{}，错误信息：", fileName, bucketName, e);
                }
            }
            return resultList;
        }
        return Collections.emptyList();
    }

    /**
     * 获取预览地址
     *
     * @param fileName  文件名
     * @param bucketName 桶名
     * @return 预览地址
     */
    public String getPreviewUrl(String fileName, String bucketName) {
        if (isNotNullOrEmpty(fileName)) {
            bucketName = isNotNullOrEmpty(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
                if (null != minioConfig.getPreviewExpiry()) {
                    String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET).bucket(bucketName).object(fileName)
                            .expiry(minioConfig.getPreviewExpiry(), TimeUnit.HOURS).build());
                    log.info("有时限文件预览地址为：{}，文件名：{}，bucket名：{}，有效时间为：{}", presignedObjectUrl, fileName, bucketName, minioConfig.getPreviewExpiry());
                    return presignedObjectUrl;
                } else {
                    String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET).bucket(bucketName).object(fileName).build());
                    log.info("文件预览地址为：{}，文件名：{}，bucket名：{}，有效时间为：永久", presignedObjectUrl, fileName, bucketName);
                    return presignedObjectUrl;
                }
            } catch (Exception e) {
                log.error("预览文件地址错误，文件名为：{}，bucket名为：{}，错误信息为：", fileName, bucketName, e);
            }
        }
        return null;
    }

    /**
     * 下载文件
     *
     * @param response 响应
     * @param fileName 文件名
     * @param bucketName 桶名
     */
    public void downloadFile(HttpServletResponse response, String fileName, String bucketName) {
        InputStream inputStream = null;
        if (isNotNullOrEmpty(fileName)) {
            bucketName = isNotNullOrEmpty(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                StatObjectResponse objectStat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
                response.setContentType(objectStat.contentType());
                response.setCharacterEncoding("UTF-8");
                inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
                IOUtils.copy(inputStream, response.getOutputStream());
                log.info("文件下载成功，文件名称：{}，bucket名为：{}", fileName, bucketName);
            } catch (Exception e) {
                log.error("文件下载失败，文件名称：{}，错误信息：", fileName, e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        log.error("输入流关闭失败，文件名：{}，错误信息：", fileName, e);
                    }
                }
            }
        }
    }

    /**
     * 删除文件
     *
     * @param fileName 文件名
     * @param bucketName 桶名
     * @return 删除结果
     */
    public String delFile(String fileName, String bucketName) {
        if (isNotNullOrEmpty(fileName)) {
            bucketName = isNotNullOrEmpty(bucketName) ? bucketName : minioConfig.getBucketName();
            try {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
                log.info("文件删除成功，文件名称为：{}，bucket为：{}", fileName, bucketName);
                return "success";
            } catch (Exception e) {
                log.error("删除文件失败，文件名称为：{}，bucket为：{}，错误信息：", bucketName, fileName, e);
                return "删除文件失败，请刷新后重试";
            }
        }
        return "文件不能为空";
    }

    /**
     * 判断字符串是否为空或空字符串
     *
     * @param str 字符串
     * @return true：为空或空字符串，false：不为空或空字符串
     */
    public static boolean isNotNullOrEmpty(String str) {
        return str != null && !str.isEmpty();
    }

}
